package com.base.themvx

import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.content.res.Resources
import android.util.Log
import androidx.annotation.Keep
import java.lang.ref.WeakReference
import java.util.Locale
import kotlin.system.exitProcess


/**
 ******************(^_^)***********************<br>
 * Author: fee(QQ/WeiXin:1176610771)<br>
 * Date: 2022/8/19<br>
 * Time: 14:11<br>
 * <P>DESC:
 * App 内部支持语言管理者
 * </p>
 * ******************(^_^)***********************
 */
class LanguageManager private constructor() {

    companion object Configs {

        internal val isDebug = BuildConfig.DEBUG
        private val mManager: LanguageManager by lazy(LazyThreadSafetyMode.NONE) {
            LanguageManager()
        }

        var mIsNeedKeepFontSize = true

        /**
         * 中文模式
         */
        val THE_CHINESE_MODE by lazy(LazyThreadSafetyMode.NONE) {
            ChineseMode()
        }

        /**
         * 英语语言模式
         */
        val THE_ENGLISH_MODE by lazy(LazyThreadSafetyMode.NONE) {
            EnglishMode()
        }

        /**
         * 韩语语言模式
         */
        val THE_KOREA_MODE by lazy(LazyThreadSafetyMode.NONE) {
            KoreaMode()
        }

        /**
         * 当前的 App 语言模式
         * 本组件默认设置的 为中文（外部也可以更改）：def = [THE_CHINESE_MODE]
         */
        @set:JvmName("languageMode")
        @get:JvmName("curLanguageMode")
        var curLanguageMode: LanguageMode = THE_CHINESE_MODE

        /**
         * 初始化语言管理者
         * 1、重置为上次用户已切换的语言
         * 2、初始化默认的语言(如果本组件默认的语言与系统当前的默认语言不一致，则会主动切换一次)
         */
        @JvmStatic
        fun init(context: Context, lastLocale: Locale?) {
            mManager.initConfig(context, lastLocale)
        }

        /**
         * 当前是否为阿语语言
         */
        var isCurArLang = false

        /**
         * 添加语言切换的观察者
         */
        @JvmStatic
        fun addLanguageModeObserver(ob: ILanguageModeObserver) {
            mManager.addLangModeObserver(ob)
        }

        /**
         * 切换App语言模式
         */
        fun directSwitchLanguageMode(context: Context, targetLanguageMode: LanguageMode): Boolean {
            val isSwitched = mManager.switchLanguageMode(context, targetLanguageMode)
            if (isSwitched) {
                curLanguageMode = targetLanguageMode
            }
            return isSwitched
        }

        /**
         * 根据 Locale 匹配到自定义的语言模式
         * @param locale Locale
         * @return LanguageMode
         */
        fun matchDefLanguageModeByLocale(locale: Locale): LanguageMode {
            return mManager.matchDefLanguageModeByLocale(locale)
        }

        /**
         * 获取对应语言的 key 的值
         * @param theKey Int
         * @return CharSequence
         */
        @JvmStatic
        fun getLangValue(theKey: Int): CharSequence {
            if (theKey == 0) {
                return "0"
            }
            return mManager.getLangValueOfKey(theKey)
        }

        @JvmStatic
        fun getMe() = mManager

        /**
         * 让已切换的语言配置信息应用到当前的　[context]
         * 可以用来在一个App的闪屏页(Activity)或者主页面(Activity)加载布局视图之前应用，用来改变整个App的页面语言
         * @param context 要被应用本App内已切换了语言的上下文;　如果[context]为　Activity，被影响后，后面所有启动的Activity都会影响
         * 注：需要在[init]　方法之后，一般在主页面调用(可能需要Activity常在)
         */
        fun effectContextConfig(context: Context) {
            val curRes = context.resources
            val curConfig = curRes.configuration
            var curFontScale = curConfig.fontScale
            val curDisplayMetrics = curRes.displayMetrics
            if (mIsNeedKeepFontSize) {
                curFontScale = curConfig.fontScale
                if (curFontScale != 1.0f) {
                    curConfig.fontScale = 1.0f
                }
            }
            if (isDebug) {
                Log.i(
                    "LanguageManager",
                    "--> effectContextConfig() context = $context, curFontScale = $curFontScale, src configuration = $curConfig"
                )
            }
            curConfig.setLocale(curLanguageMode.locale)
//            configuration.locale = curLanguageMode.locale
            curRes.updateConfiguration(curConfig, curDisplayMetrics)
            if (isDebug) {
                Log.i(
                    "LanguageManager",
                    "--> effectContextConfig() after configuration = $curConfig"
                )
            }
        }

        /**
         * 重启App的方案
         */
        fun restartApp(context: Context) {
            context.packageManager.getLaunchIntentForPackage(context.packageName)?.let {
                it.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                context.startActivity(it)
                exitProcess(0)
            }
        }

        fun getConfigedContext(context: Context): Context {
            val appRes = getMe().getAppRes()
            val appConfig = appRes.configuration
            appConfig.fontScale = 1f
            return context.createConfigurationContext(appConfig)
        }
    }

    private lateinit var mAppContext: Context

    /**
     * 切换语言的附加：当切换到阿语或者从阿语切换到其他语言时，
     * 会需要页面的布局方向的切换：LTR -> RTL; 或者　RTL -> LTR;
     */
    private var mIsChangedLayoutDirection: Boolean = false

    fun initConfig(context: Context, lastLocale: Locale?) {
        mAppContext = context.applicationContext
//        context.resources.configuration.locales[0] //Api 24
        //当前系统的 Locale，注意：如果在App非冷启动的第二次调用该方法初始化时，此时 context可能已经是被切换了locale的
        val curConfig = context.resources.configuration
        val curLocale = curConfig.locale
        val language = curLocale.language
        val country = curLocale.country
        val curLangMode = if (lastLocale != null) {//之前所记录的 不为空
            matchDefLanguageModeByLocale(lastLocale)
        } else {//没有上一次的语言模式,则匹配默认的
            matchDefLanguageModeByLocale(curLocale)
        }
        curLanguageMode = curLangMode
        val isNeedSwitch: Boolean = !curLangMode.isSameAsLocale(curLocale)
        if (isDebug) {
            Log.e(
                "LanguageManager",
                "--> initConfig() context = $context,src language = $language,country = $country," +
                        " isNeedSwitch = $isNeedSwitch"
            )
        }
        if (isNeedSwitch) {
            switchLanguageMode(context, curLangMode, true)
        } else {
            //todo: 初始化时如果上次用户切换的语言mode正好是英语，则也要赋值一个　Res
            if ("ar" == curLangMode.getLanguage()) {
                isCurArLang = true
            }
            val config = Configuration(curConfig)
            if (mIsNeedKeepFontSize) {
                config.fontScale = 1.0f
            }
            config.locale = curLangMode.locale
            mCurAppRes = Resources(
                context.assets,
                context.resources.displayMetrics,
                config
            )
            curLangMode.loadLanguageRes()
        }
    }

    /**
     * @return true: 切换了; false: 未切换
     */
    fun switchLanguageMode(
        context: Context,
        targetLanguageMode: LanguageMode,
        isForceSwitch: Boolean = false
    ): Boolean {
        val curLangMode = curLanguageMode
        if (!isForceSwitch && targetLanguageMode.isSameLangMode(curLangMode)) {
            return false
        }
        val isLastArLang = "ar" == curLangMode.getLanguage()
        val isNowArLang = "ar" == targetLanguageMode.getLanguage()
        isCurArLang = isNowArLang
        mIsChangedLayoutDirection = isLastArLang || isNowArLang
        targetLanguageMode.loadLanguageRes()
        val targetLocale = targetLanguageMode.locale
        if (isDebug) {
            Log.i(
                "LanguageManager",
                "--> switchLanguageMode() targetLanguageMode = $targetLanguageMode "
            )
        }
        val isNeedKeepFontSize = mIsNeedKeepFontSize
        //系统资源方式的切换
        val curRes = context.resources
        val curConfig = curRes.configuration
        val curFontScale = curConfig.fontScale
        if (isNeedKeepFontSize && curFontScale != 1.0f) {
            curConfig.fontScale = 1.0f
//            val curDisplayMetrics = curRes.displayMetrics
//            curDisplayMetrics.scaledDensity = curDisplayMetrics.density
        }
        curConfig.locale = targetLocale
        curRes.updateConfiguration(curConfig, curRes.displayMetrics) //这种方案需要 重新创建Activity或者重启App
        //同时 Application 级的也切换掉
        val appRes = mAppContext.resources
        val appConfig = appRes.configuration
        if (isNeedKeepFontSize) {
            appConfig.fontScale = 1f
        }

        appConfig.locale = targetLocale
        appRes.updateConfiguration(appConfig, appRes.displayMetrics)
        dispatchLanguageModeChanged(targetLanguageMode)
        //todo: 一定要自己维持一个　Resources,不然在应用使用过程中如果跳转到App应用外，会导致Resources被变更
        val config = Configuration(appConfig)
        val res = Resources(context.assets, appRes.displayMetrics, config)
        mCurAppRes = res
        return true
    }


    private var mIsAddedObserver = false

    /**
     * 语言切换的监听者数据集
     */
    private val mLanguageModeObservers by lazy(LazyThreadSafetyMode.NONE) {
        mIsAddedObserver = true
        mutableListOf<WeakReference<ILanguageModeObserver>>()
    }

    /**
     * 添加语言切换的观察者
     */
    fun addLangModeObserver(ob: ILanguageModeObserver?) {
        if (ob != null) {
            mLanguageModeObservers.add(WeakReference(ob))
        }
    }


    private fun dispatchLanguageModeChanged(newLanguageMode: LanguageMode) {
        if (mIsAddedObserver) {
            mLanguageModeObservers.forEach {
                val observer = it.get()
                observer?.onLanguageModeChanged(newLanguageMode)
            }
        }
    }

    /**
     * 获取对应语言的 语言值
     * @param theKey Int
     * @return CharSequence
     */
    fun getLangValueOfKey(theKey: Int): CharSequence {
        if (theKey == 0) {
            return ""
        }
        val v = curLanguageMode.getLanguageValue(theKey)
        if (v.isBlank()) {
            return curLanguageMode.loadLangValueFromRes(mAppContext, theKey)
        }
        return v
    }


    /**
     * 根据 Locale 匹配到自定义的语言模式
     * @param locale Locale
     * @return LanguageMode
     */
    fun matchDefLanguageModeByLocale(locale: Locale): LanguageMode {
        return when (locale.language) {
            "zh" -> {
                THE_CHINESE_MODE
            }

            "en" -> {
                THE_ENGLISH_MODE
            }

//            "ko" -> {
//                THE_KOREA_MODE
//            }

            else -> {
                mLanguageModeMatcher?.onMatchLanguageMode(locale) ?: THE_ENGLISH_MODE
            }
        }
    }

    private var mCurAppRes: Resources? = null

    /**
     * 注：要先调用 [initConfig] 后再使用
     * //todo: 一定要自己维持一个　Resources,不然 mAppContext 会被其他的地方给重置掉
     * //todo: reCreate() 方案不会出现这样的问题？？？
     */
    fun getAppRes(): Resources {
//        Log.e("LanguageManager","--> getAppRes()")
        //mAppContext.resources　有可能在有些页面被更改
        return mCurAppRes ?: mAppContext.resources
    }

    /**
     * 外部扩展的 语言匹配者，目的为，如果本组件内部匹配不到，外部还可以扩展所支持的语种
     */
    @set:JvmName("languageModeMatcher")
    var mLanguageModeMatcher: ILanguageModeMatcher? = null

    /**
     * 判断当前是否因为语言的切换导致布局方向发生了改变
     * @param isResetState true: 获取后，把状态重置掉
     */
    fun isLayoutDirectionChanged(isResetState: Boolean = false): Boolean {
        val isChanged = mIsChangedLayoutDirection
        if (isResetState) {
            mIsChangedLayoutDirection = false
        }
        return isChanged
    }

    @Keep
    interface ILanguageModeMatcher {
        /**
         * 根据 Locale 匹配所支持的语言模式
         * @return LanguageMode?
         */
        fun onMatchLanguageMode(locale: Locale): LanguageMode?
    }


    /**
     * 语言模式变更的观察者
     */
    interface ILanguageModeObserver {

        /**
         * 语言模式变更了
         * @param theLanguageMode LanguageMode 当前的语言模式
         * @return true: 处理了; false: 不处理(一般不处理)
         */
        fun onLanguageModeChanged(theLanguageMode: LanguageMode): Boolean

    }


}